package engine;

import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingWorker;
import ui.SimulationUI;
import utilities.MatLabCOM;
import utilities.RandomNumeric;

public class PopulationGenerator extends SwingWorker<Population, Integer> {

    private RandomNumeric rand;
    private MatLabCOM matlab;
    private Constraint constraint;
    private Integer populationSizeToReach;
    private SimulationUI gui;
    private Integer maxComputation;

    public PopulationGenerator(RandomNumeric rand, MatLabCOM matlab, Constraint constraint,
            Integer populationSizeToReach, SimulationUI gui, Integer maxComputation) {
        this.rand = rand;
        this.matlab = matlab;
        this.constraint = constraint;
        this.populationSizeToReach = populationSizeToReach;
        this.gui = gui;
        this.maxComputation = maxComputation;
    }

    @Override
    protected Population doInBackground() throws Exception {
        return generate();
    }

    @Override
    protected void process(List<Integer> values) {
        for (Integer val : values) {
            gui.updateProgressGenPop((int) val);
        }
    }
    
    /*
     * Retourne null si la génération échoue (contraintes trop fortes)
     */
    public Population generate() {

        ArrayList<Candidate> candidates = new ArrayList<Candidate>();

        Candidate currentCand;
        double progress = 0.;
        
        int loopCount = 0;

        do {
            loopCount++;
            if(loopCount == maxComputation){
                if(progress == 0.)
                    this.gui.displayErrorPopup(this.gui, "Unable to generate the population, please check the constraints. The problem could have no solutions.");
                else
                    this.gui.displayErrorPopup(this.gui, "Population generation reached maximum computations, please reduce the population size or increase maximum computations.");
                return null;
            }
            
            currentCand = generateCandidate();

            if (currentCand.matchEquations(constraint.getEquations(), matlab)) {
                candidates.add(currentCand);
                progress = (double) candidates.size() * 100 / populationSizeToReach;
                //gui.updateProgressGenPop((int)progress);
                publish((int) progress);//Fonctionne pas comme prévu
                System.out.println("Progress Gen Pop = " + (int) progress);
            }

            //On continue de générer tant qu'on a pas assez d'individus
        } while (candidates.size() < populationSizeToReach);

        return new Population(candidates);
    }

    /*
     * Génére un individu dont les valeurs sont comprises entre les bornes des contraintes
     */
    private Candidate generateCandidate() {
        ArrayList<Double> vect = new ArrayList<Double>();

        for (int i = 0; i < constraint.getBornesInf().size(); i++) {
            vect.add(this.rand.doubleInInterval(constraint.getBornesInf().get(i), constraint.getBornesSup().get(i)));
        }

        return new Candidate(vect);
    }
}
